package org.jeecg.modules.xindian.reconciliation.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.DictModel;

import org.jeecg.modules.xindian.reconciliation.controller.enums.InvoiceNeedFlag;
import org.jeecg.modules.xindian.reconciliation.controller.req.SalesManStaticUpdate;
import org.jeecg.modules.xindian.reconciliation.dto.rsp.DataSumStatisticsRow;
import org.jeecg.modules.xindian.reconciliation.dto.rsp.DataSumStatisticsRsp;
import org.jeecg.modules.xindian.reconciliation.dto.rsp.PlatformCodeSumStatisticsRow;
import org.jeecg.modules.xindian.reconciliation.dto.rsp.ProjectSumStatisticsRow;
import org.jeecg.modules.xindian.reconciliation.controller.req.TrendReqInfo;
import org.jeecg.modules.xindian.reconciliation.controller.rsp.CommonDataStatic;
import org.jeecg.modules.xindian.reconciliation.controller.rsp.RankAndProportionRsp;
import org.jeecg.modules.xindian.reconciliation.controller.rsp.SalemanAndChannelProportionRsp;
import org.jeecg.modules.xindian.reconciliation.controller.rsp.TrendRspInfo;
import org.jeecg.modules.xindian.reconciliation.dto.*;
import org.jeecg.modules.xindian.reconciliation.entity.InsuranceStatistics;
import org.jeecg.modules.xindian.reconciliation.entity.PolicySettlementStatistics;
import org.jeecg.modules.xindian.reconciliation.entity.Salesman;
import org.jeecg.modules.xindian.reconciliation.entity.SalesmanManagerRate;
import org.jeecg.modules.xindian.reconciliation.enums.ChannelMatchState;
import org.jeecg.modules.xindian.reconciliation.enums.DeleteFlagEnum;
import org.jeecg.modules.xindian.reconciliation.mapper.InsuranceStatisticsMapper;
import org.jeecg.modules.xindian.reconciliation.service.IInsuranceStatisticsService;
import org.jeecg.modules.xindian.reconciliation.service.IPolicySettlementStatisticsService;
import org.jeecg.modules.xindian.reconciliation.enums.StatisticsPolicyStateEnum;
import org.jeecg.modules.xindian.reconciliation.service.ISalesmanManagerRateService;
import org.jeecg.modules.xindian.reconciliation.service.ISalesmanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Description: insurance_statistics
 * @Author: jeecg-boot
 * @Date: 2023-07-22
 * @Version: V1.0
 */
@Service
@Slf4j
public class InsuranceStatisticsServiceImpl extends ServiceImpl<InsuranceStatisticsMapper, InsuranceStatistics> implements IInsuranceStatisticsService {
    @Autowired
    private IPolicySettlementStatisticsService policySettlementStatisticsService;
    @Autowired
    private ISysBaseAPI sysBaseAPI;
    @Autowired
    private ISalesmanService salesmanService;
    @Autowired
    private ISalesmanManagerRateService salesmanManagerRateService;


    @Override
    public List<MatchBaoDanHao> matchBaoHan(List<MatchBaoDanHao> baoDanHaos) {
        List<InsuranceStatistics> findMatch = lambdaQuery().in(InsuranceStatistics::getPolicyNo, baoDanHaos.stream().map(MatchBaoDanHao::getPolicyNo).collect(Collectors.toList())).list();
        List<String> saleMan = policySettlementStatisticsService.lambdaQuery().isNotNull(PolicySettlementStatistics::getPolicyNo).list().stream().map(PolicySettlementStatistics::getPolicyNo).collect(Collectors.toList());
        List<InsuranceStatistics> maths = new ArrayList<>();
        Map<String, InsuranceStatistics> insuranceStatisticsMap = findMatch.stream().collect(Collectors.toMap(InsuranceStatistics::getPolicyNo, Function.identity()));
        for (MatchBaoDanHao baoDanHao : baoDanHaos) {
            InsuranceStatistics findOne = insuranceStatisticsMap.get(baoDanHao.getPolicyNo());
            if (findOne == null) {
                baoDanHao.setMatchState("无此保单");
            } else {
                if (saleMan.contains(findOne.getPolicyNo())) {
                    baoDanHao.setMatchState("业务员订单");
                } else {
                    if (findOne.getChannelMatchState().equals(ChannelMatchState.WPP)) {
                        baoDanHao.setMatchState("匹配成功");
                        findOne.setChannelProvider(baoDanHao.getMerchantName());
                        findOne.setChannelMatchState(ChannelMatchState.YPP);
                        maths.add(findOne);
                    } else {
                        baoDanHao.setMatchState("历史已匹配成功");
                    }
                }
            }
        }
        maths.forEach(one -> {
            updateById(one);
        });
        return baoDanHaos;
    }

    @Override
    public List<MatchProjectName> matchProject(List<MatchProjectName> matchProjectNames) {
        List<InsuranceStatistics> findMatch = lambdaQuery().list();
        //查询业务员订单
        List<String> saleMan = policySettlementStatisticsService.lambdaQuery().isNotNull(PolicySettlementStatistics::getPolicyNo).list().stream().map(PolicySettlementStatistics::getPolicyNo).collect(Collectors.toList());
        List<InsuranceStatistics> maths = new ArrayList<>();
        Map<String, InsuranceStatistics> insuranceStatisticsMap = findMatch.stream().collect(Collectors.toMap(insuranceStatistics -> insuranceStatistics.getProjectName() + insuranceStatistics.getPolicyHolderName(), Function.identity(), (o, n) -> n));
        for (MatchProjectName baoDanHao : matchProjectNames) {
            InsuranceStatistics findOne = insuranceStatisticsMap.get(baoDanHao.getProjectName() + baoDanHao.getPolicyHolderName());
            if (findOne == null) {
                baoDanHao.setMatchState("无此保单");
            } else {
                if (saleMan.contains(findOne.getPolicyNo())) {
                    baoDanHao.setMatchState("业务员订单");
                } else {
                    if (findOne.getChannelMatchState().equals(ChannelMatchState.WPP)) {
                        baoDanHao.setMatchState("匹配成功");
                        findOne.setChannelProvider(baoDanHao.getMerchantName());
                        findOne.setChannelMatchState(ChannelMatchState.YPP);
                        maths.add(findOne);
                    } else {
                        baoDanHao.setMatchState("历史已匹配成功");
                    }
                }
            }
        }
        maths.forEach(one -> {
            updateById(one);
        });
        return matchProjectNames;
    }

    @Override
    public DataSumStatisticsRsp dataSumStatistics(StatisticsQuery dataStatistics) {
        DataSumStatisticsRsp dataSumStatisticsRsp = new DataSumStatisticsRsp();
        dataSumStatisticsRsp.setInsuranceTotal(getBaseMapper().queryInsuranceTotal(dataStatistics));
        BigDecimal pretotal = getBaseMapper().queryPremiumTotal(dataStatistics);
        dataSumStatisticsRsp.setPremiumTotal(pretotal == null ? BigDecimal.ZERO : pretotal);
        dataSumStatisticsRsp.setSurrenderTotal(getBaseMapper().querySurrenderTotal(dataStatistics));
        BigDecimal premiumTotal = getBaseMapper().querySurrenderPremiumTotal(dataStatistics);
        dataSumStatisticsRsp.setSurrenderPremiumTotal(premiumTotal == null ? BigDecimal.ZERO : premiumTotal);
        return dataSumStatisticsRsp;
    }

    @Override
    public IPage<ProjectSumStatisticsRow> queryProjectSumStatisticsRow(Page page, StatisticsQuery dataStatistics) {
        return getBaseMapper().queryProjectSumStatisticsRow(page, dataStatistics);
    }

    @Override
    public List<ProjectSumStatisticsRow> queryProjectSumStatisticsRowAll(StatisticsQuery dataStatistics) {
        return getBaseMapper().queryProjectSumStatisticsRowAll(dataStatistics);
    }

    @Override
    public IPage<DataSumStatisticsRow> queryDataSumStatisticsRow(Page page, StatisticsQuery dataStatistics) {
        return getBaseMapper().queryDataSumStatisticsRow(page, dataStatistics);
    }

    @Override
    public List<DataSumStatisticsRow> queryDataSumStatisticsRowAll(StatisticsQuery dataStatistics) {
        return getBaseMapper().queryDataSumStatisticsRowAll(dataStatistics);
    }

    @Override
    public IPage<PlatformCodeSumStatisticsRow> queryInsuranceSumStatisticsRow(Page page, StatisticsQuery dataStatistics) {
        return getBaseMapper().queryInsuranceSumStatisticsRow(page, dataStatistics);
    }

    @Override
    public List<PlatformCodeSumStatisticsRow> queryInsuranceSumStatisticsRowAll(StatisticsQuery dataStatistics) {
        return getBaseMapper().queryInsuranceSumStatisticsRowAll(dataStatistics);
    }

    @Override
    public List<InsuranceStatistics> loadByInsuranceAndPlatform(String insurance, List<String> platform, Boolean conditionByPayTime, Date lastMounth) {
        LambdaQueryChainWrapper<InsuranceStatistics> query = lambdaQuery().eq(InsuranceStatistics::getInsuranceCompany, insurance);
        query.in(InsuranceStatistics::getPlatformCode, platform);
        query.in(InsuranceStatistics::getPolicyState, Arrays.asList(StatisticsPolicyStateEnum.YCB));
        DateTime start = DateUtil.beginOfMonth(lastMounth);
        DateTime end = DateUtil.endOfMonth(lastMounth);
        //查询上个月得数据信息
        if (conditionByPayTime) {
            query.between(InsuranceStatistics::getPayTime, start, end);
        } else {
            query.between(InsuranceStatistics::getKaiBiaoTime, DateUtil.format(start, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(end, "yyyy-MM-dd HH:mm:ss"));
        }
        query.isNotNull(InsuranceStatistics::getPolicyNo);
        return query.list();
    }

    @Override
    public List<InsuranceStatistics> loadByPolicyHolderName(List<String> policyHolderNames, Date date) {
        if (CollectionUtils.isEmpty(policyHolderNames)) {
            return new ArrayList<>();
        }
        LambdaQueryChainWrapper<InsuranceStatistics> query = lambdaQuery().in(InsuranceStatistics::getPayAccountName, policyHolderNames);
        DateTime start = DateUtil.beginOfMonth(date);
        DateTime end = DateUtil.endOfMonth(date);
        query.between(InsuranceStatistics::getPayTime, start, end);
        query.in(InsuranceStatistics::getPolicyState, Arrays.asList(StatisticsPolicyStateEnum.YCB));
        query.isNotNull(InsuranceStatistics::getPolicyNo);
        return query.list();
    }

    @Override
    public List<InsuranceStatistics> loadByPolicyNo(List<String> policyNos) {
        return lambdaQuery().in(InsuranceStatistics::getPolicyNo, policyNos).list();
    }

    @Override
    public List<InsuranceStatistics> loadByInsuranceAreaAndPlatform(String insurance, List<String> platform, String channelName, Date lastMounth) {
        LambdaQueryChainWrapper<InsuranceStatistics> query = lambdaQuery();
        DateTime start = DateUtil.beginOfMonth(lastMounth);
        DateTime end = DateUtil.endOfMonth(lastMounth);
        Assert.notEmpty(platform, "平台配置不能为空");
        Assert.notEmpty(insurance, "保险机构不能为空");
        query.in(InsuranceStatistics::getPlatformCode, platform);
        query.eq(InsuranceStatistics::getInsuranceCompany, insurance);
        query.in(InsuranceStatistics::getPolicyState, Arrays.asList(StatisticsPolicyStateEnum.YCB));
        query.between(InsuranceStatistics::getPayTime, start, end);
        if (StringUtils.isNotBlank(channelName)) {
            query.eq(InsuranceStatistics::getChannelMatchState, ChannelMatchState.YPP);
            query.eq(InsuranceStatistics::getChannelProvider, channelName);
        }
        query.isNotNull(InsuranceStatistics::getPolicyNo);
        return query.list();
    }

    @Override
    public TrendRspInfo trend(TrendReqInfo trendReqInfo) {
        Assert.notNull(trendReqInfo.getStartDate(), "开始时间不能为空");
        Assert.notNull(trendReqInfo.getEndDate(), "结束时间不能为空");
        TrendDto all = getBaseMapper().trend(trendReqInfo, "ALL");
        TrendDto oht = getBaseMapper().trend(trendReqInfo, "TBZ");
        TrendRspInfo teInfo = new TrendRspInfo();
        teInfo.setPremiumTotal(all.getAmt());
        teInfo.setPolicyTotal(all.getTotal());
        teInfo.setRefundTotal(oht.getTotal());
        teInfo.setRefundAmtTotal(oht.getAmt());
        teInfo.setAmtList(getBaseMapper().trendAmt(trendReqInfo));
        teInfo.setNumberList(getBaseMapper().trendNumber(trendReqInfo));
        return teInfo;
    }

    @Override
    public RankAndProportionRsp rankAndProportion(TrendReqInfo trendReqInfo) {
        RankAndProportionRsp rankAndProportionRsp = new RankAndProportionRsp();
        List<CommonDataStatic> areaRank = getBaseMapper().queryAreaRank(trendReqInfo);
        updateRank(areaRank);
        List<CommonDataStatic> plankRank = getBaseMapper().queryPlankRank(trendReqInfo);
        updateRank(plankRank);
        rankAndProportionRsp.setAreaInfo(areaRank);
        updateDict(areaRank, "DZQY");
        rankAndProportionRsp.setPlatformInfo(plankRank);
        updateDict(plankRank, "JYPTBM");
        return rankAndProportionRsp;
    }

    @Override
    public SalemanAndChannelProportionRsp salesmanAndChannel(TrendReqInfo trendReqInfo) {
        SalemanAndChannelProportionRsp salemanAndChannelProportionRsp = new SalemanAndChannelProportionRsp();
        List<CommonDataStatic> channelRank = getBaseMapper().queryChannelRank(trendReqInfo);
        List<CommonDataStatic> salesmanRank = getBaseMapper().querySalesmanNameRank(trendReqInfo);
        //处理占比
        updateRank(channelRank);
        updateRank(salesmanRank);
        salemanAndChannelProportionRsp.setChannelInfo(channelRank);
        salemanAndChannelProportionRsp.setSalemanInfo(salesmanRank);
        return salemanAndChannelProportionRsp;
    }

    @Override
    public List<CommonDataStatic> premiumRank(TrendReqInfo trendReqInfo) {
        return getBaseMapper().typePremium(trendReqInfo);
    }

    @Override
    public void loadData() {
        List<InsuranceStatistics> guangrun = insuranceStatistics("guangrun");
        List<InsuranceStatistics> xierong = insuranceStatistics("xierong");
        List<InsuranceStatistics> zhonglian = insuranceStatistics("zhonglian");
        //判断哪些是更新 哪些是插入
        guangrun.addAll(xierong);
        guangrun.addAll(zhonglian);
        List<String> ids = guangrun.stream().map(InsuranceStatistics::getId).collect(Collectors.toList());
        List<InsuranceStatistics> fromDb =  getBaseMapper().selectBatchIds(ids);
        Map<String, InsuranceStatistics> fromDbMap = fromDb.stream().collect(Collectors.toMap(InsuranceStatistics::getId, Function.identity()));
        List<String> dateHave = fromDb.stream().map(InsuranceStatistics::getId).collect(Collectors.toList());
        List<InsuranceStatistics> updateDATA = new ArrayList<>();
        List<InsuranceStatistics> addDATA = new ArrayList<>();
        guangrun.forEach(one -> {
            if (dateHave.contains(one.getId())) {
                InsuranceStatistics fromdb = fromDbMap.get(one.getId());
                one.setChannelProvider(fromdb.getChannelProvider());
                one.setChannelMatchState(fromdb.getChannelMatchState());
                one.setSalesmanName(fromdb.getSalesmanName());
                one.setSalesmanId(fromdb.getSalesmanId());
                one.setInvoiceNeedFlag(fromdb.getInvoiceNeedFlag());
                one.setInvoiceStatus(fromdb.getInvoiceStatus());
                one.setInvoiceDownloadUrl(fromdb.getInvoiceDownloadUrl());
                paddingInvoiceFlag(one);
                updateDATA.add(one);
            } else {
                paddingInvoiceFlag(one);
                addDATA.add(one);
            }
        });
        updateBatchById(updateDATA);
        saveBatch(addDATA);
    }

    /**
     * 处理是否需要开发票
     * @param one
     */
    private static void paddingInvoiceFlag(InsuranceStatistics one) {
        if("0".equals(one.getIsenctry())&&InvoiceNeedFlag.N.equals(one.getInvoiceNeedFlag())){
            //只处理中联金安的大家渠道的发票数据
            if("DJCX".equals(one.getInsuranceCompany())){
                one.setInvoiceNeedFlag(InvoiceNeedFlag.Y);
            }
        }
    }


    @Override
    public void processOneDaySalemanInfo() {
        Map<String, Salesman> salesmen = salesmanService.lambdaQuery().eq(Salesman::getDeleteFlag, DeleteFlagEnum.N.name()).list().stream().collect(Collectors.toMap(Salesman::getId, Function.identity()));
        Map<String, List<SalesmanManagerRate>> allList = salesmanManagerRateService.listAllEnableRate().stream().collect(Collectors.groupingBy(SalesmanManagerRate::getSalesmanId));
        getBaseMapper().cleanSalesmanNameAndId();
        //计算管理的企业，然后根据企业名称作为条件更新数据
        allList.forEach((one, list) -> {
            Salesman salesman = salesmen.get(one);
            Set<String> company = list.stream().map(SalesmanManagerRate::getCompany).collect(Collectors.toSet());
            if(CollectionUtils.isNotEmpty(company)){
                SalesManStaticUpdate salesManStaticUpdate = new SalesManStaticUpdate();
                salesManStaticUpdate.setSalesmanId(salesman.getId());
                salesManStaticUpdate.setSalesmanName(salesman.getName());
                salesManStaticUpdate.setBegin(DateUtil.parseDate("2012-01-01 00:00:00"));
                salesManStaticUpdate.setEnd(DateUtil.endOfDay(new Date()));
                salesManStaticUpdate.setCompanys(new ArrayList<>(company));
                getBaseMapper().updateSalesmanNameAndId(salesManStaticUpdate);
            }
        });

    }



    public List<InsuranceStatistics> insuranceStatistics(String ds) {

        try {
            DynamicDataSourceContextHolder.push(ds);
            //加载一个月之前的数据
//            if(!"xierong".equals(ds)){
//                getBaseMapper().reconciliationDataProcess();
//            }
            Date begin = DateUtils.addDays(DateUtil.beginOfMonth(new Date()), -31*3);
            List<InsuranceStatistics> reconciliations = getBaseMapper().loadData(begin);
            reconciliations.forEach(one -> {
                one.setPlatform(ds);
            });
            return reconciliations;
        } finally {
            DynamicDataSourceContextHolder.poll();
        }
    }

    private void updateDict(List<CommonDataStatic> statics, String dictCode) {
        List<DictModel> dictModels = sysBaseAPI.getDictItems(dictCode);
        Map<String, DictModel> modelMap = dictModels.stream().collect(Collectors.toMap(DictModel::getValue, Function.identity()));
        statics.forEach(commonDataStatic -> {
            DictModel tagModel = modelMap.get(commonDataStatic.getTag());
            String tag = tagModel == null ? commonDataStatic.getTag() : tagModel.getText();
            commonDataStatic.setTag(tag);
        });
    }

    private void updateRank(List<CommonDataStatic> statics) {
        AtomicReference<BigDecimal> total = new AtomicReference<>(BigDecimal.ZERO);
        statics.forEach(commonDataStatic -> {
            BigDecimal result = total.get().add(commonDataStatic.getAmt());
            total.set(result);
        });
        statics.forEach(commonDataStatic -> {
            if (total.get().compareTo(BigDecimal.ZERO) > 0 && commonDataStatic.getAmt().compareTo(BigDecimal.ZERO) > 0) {
                commonDataStatic.setRank(commonDataStatic.getAmt().divide(total.get(), 4, RoundingMode.HALF_DOWN).multiply(BigDecimal.valueOf(100)));
            } else {
                commonDataStatic.setRank(BigDecimal.ZERO);
            }
        });
    }
}
